Skip to content

feat(payouts): surface vop response - #2074

Merged
AmitsinghTanwar007 merged 10 commits into
mainfrom
feat/vop-changes
Aug 11, 2026
Merged

feat(payouts): surface vop response#2074
AmitsinghTanwar007 merged 10 commits into
mainfrom
feat/vop-changes

Conversation

@heykulthe

@heykulthe heykulthe commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Description

Surfaces Deutsche Bank's Verification-of-Payee (VoP) outcome on the payout eligibility response, so the caller can tell why a payee was refused and can reconcile the check afterwards.

Motivation and Context

A VoP refusal was previously indistinguishable from any other ineligible payee, the caller got a status and nothing else, so a merchant could not be told whether the IBAN failed to match the payee name, or the payee simply could not be checked. NMTC and NOAP now carry the verdict and Deutsche Bank's own explanation.

Additional Changes

  • This PR modifies the API contract
  • This PR modifies application configuration/environment variables

How did you test it?

Payout Create Response:

Payouts that result in VOP MTCH/CMTC result in additional info being surfaced to merchant in metadata whilst if it's a NMTC/NOAP, error_code and error_message fields are populated.

Create Payout Response (CMTC case):

{
    "payout_id": "payout_dcTH1SFAsaRkixQitBss",
    "merchant_id": "merchant_1786014217",
    "merchant_order_reference_id": null,
    "amount": 101,
    "currency": "EUR",
    "connector": "deutschebank",
    "payout_type": "bank",
    "payout_method_data": {
        "bank": {
            "iban": "DE945************80002",
            "bank_name": "Deutsche Bank",
            "bank_country_code": "DE",
            "bank_city": null,
            "bic": "DEU*****237",
            "account_holder_name": "John Doe"
        }
    },
    "source_bank_data": {
        "iban": "DE991************89001",
        "bank_name": null,
        "bank_country_code": null,
        "bank_city": null,
        "bic": "DEU*****237",
        "account_holder_name": "ABC Inc."
    },
    "billing": {
        "address": {
            "city": "Frankfurt",
            "country": "DE",
            "line1": "Taunusanlage 12",
            "line2": null,
            "line3": null,
            "zip": "60325",
            "state": "HE",
            "first_name": "John",
            "last_name": "Doe",
            "origin_zip": null
        },
        "phone": null,
        "email": null
    },
    "auto_fulfill": true,
    "customer_id": "payout_customer121",
    "customer": {
        "id": "payout_customer121",
        "name": "John Doe",
        "email": "payout_customer@example.com",
        "phone": "999999999",
        "phone_country_code": "+49",
        "customer_document_details": null
    },
    "client_secret": "payout_payout_dcTH1SFAsaRkixQitBss_secret_hZxcgLlpCZkJ9h1T8oRd",
    "return_url": null,
    "business_country": null,
    "business_label": null,
    "description": "any-purpose",
    "billing_descriptor": null,
    "entity_type": "Individual",
    "recurring": false,
    "metadata": {
        "vop_status": "CMTC",
        "additional_info": "The IBAN almost matches the name of the payee. This is the name of the account holder that belongs to the IBAN: CRON HOLDING GMBH. If you authorize the order anyway, this may result in the money being transferred to a payment account whose owner is not the payee you specified.",
        "eligibility_reference_id": "65992296-71d9-58fa-bc79-3f159e4a33bf"
    },
    "merchant_connector_id": "mca_l9oDd6NGEAsvyptN4H3C",
    "status": "pending",
    "error_message": null,
    "error_code": null,
    "profile_id": "pro_jaLf7s7GauSiowdxrCEY",
    "created": "2026-08-06T22:38:26.592Z",
    "connector_transaction_id": "4EA1FDCFE05957C8BBEBCFF7D98B1BD6",
    "priority": null,
    "payout_link": null,
    "email": "payout_customer@example.com",
    "name": "John Doe",
    "phone": "999999999",
    "phone_country_code": "+49",
    "unified_code": null,
    "unified_message": null,
    "payout_method_id": null
}

Get Payout Response (NMTC case)

{
   "payout_id": "payout_7AKlp8jmxZtCHm6iGuQX",
   "merchant_id": "merchant_1786014217",
   "merchant_order_reference_id": null,
   "amount": 101,
   "currency": "EUR",
   "connector": "deutschebank",
   "payout_type": "bank",
   "payout_method_data": {
       "bank": {
           "iban": "DE945************80002",
           "bank_name": "Deutsche Bank",
           "bank_country_code": "DE",
           "bank_city": null,
           "bic": "DEU*****237",
           "account_holder_name": "John Doe"
       }
   },
   "source_bank_data": {
       "iban": "DE712************40602",
       "bank_name": null,
       "bank_country_code": null,
       "bank_city": null,
       "bic": "DEU*****237",
       "account_holder_name": "ABC Inc."
   },
   "billing": {
       "address": {
           "city": "Frankfurt",
           "country": "DE",
           "line1": "Taunusanlage 12",
           "line2": null,
           "line3": null,
           "zip": "60325",
           "state": "HE",
           "first_name": "John",
           "last_name": "Doe",
           "origin_zip": null
       },
       "phone": null,
       "email": null
   },
   "auto_fulfill": true,
   "customer_id": "payout_customer121",
   "customer": {
       "id": "payout_customer121",
       "name": "John Doe",
       "email": "payout_customer@example.com",
       "phone": "999999999",
       "phone_country_code": "+49",
       "customer_document_details": null
   },
   "client_secret": "payout_payout_7AKlp8jmxZtCHm6iGuQX_secret_tFD6wiKLSsMdG8x2xnXR",
   "return_url": null,
   "business_country": null,
   "business_label": null,
   "description": "any-purpose",
   "billing_descriptor": null,
   "entity_type": "Individual",
   "recurring": false,
   "metadata": {
        "eligibility_reference_id": "29d8b78b-eb88-5f4b-b126-9bdf42b4b921"
   },
   "merchant_connector_id": "mca_l9oDd6NGEAsvyptN4H3C",
   "status": "not_permitted",
   "error_message": "The IBAN does not match the name of the payee. If you authorize the order anyway, this may result in the money being transferred to a payment account whose owner is not the payee you specified.",
   "error_code": "NMTC",
   "profile_id": "pro_jaLf7s7GauSiowdxrCEY",
   "created": "2026-08-06T22:41:41.695Z",
   "connector_transaction_id": null,
   "priority": null,
   "payout_link": null,
   "email": "payout_customer@example.com",
   "name": "John Doe",
   "phone": "999999999",
   "phone_country_code": "+49",
   "unified_code": null,
   "unified_message": null,
   "payout_method_id": null
}

Auto-applied by CI:
- cargo +nightly fmt --all
- make -C sdk generate (if applicable)
- make docs (if applicable)

This commit was automatically generated by GitHub Actions.
@hyperswitch-bot
hyperswitch-bot Bot requested a review from a team as a code owner August 6, 2026 23:31
Comment thread crates/types-traits/domain_types/src/payouts/payouts_types.rs Outdated
@heykulthe
heykulthe requested a review from a team as a code owner August 11, 2026 08:56
@heykulthe
heykulthe requested a review from Sakilmostak August 11, 2026 09:13
Auto-applied by CI:
- cargo +nightly fmt --all
- make -C sdk generate (if applicable)
- make docs (if applicable)

This commit was automatically generated by GitHub Actions.
Comment thread crates/types-traits/domain_types/src/payouts/types.rs Outdated
Comment thread crates/types-traits/domain_types/src/payouts/payouts_types.rs Outdated
Comment thread crates/types-traits/domain_types/src/payouts/payouts_types.rs Outdated
Comment thread crates/types-traits/grpc-api-types/proto/payouts.proto Outdated
Comment thread crates/types-traits/grpc-api-types/proto/payouts.proto Outdated
Sakilmostak
Sakilmostak previously approved these changes Aug 11, 2026
Sakilmostak
Sakilmostak previously approved these changes Aug 11, 2026
AkshayaFoiger
AkshayaFoiger previously approved these changes Aug 11, 2026
Comment thread crates/types-traits/domain_types/src/payouts/payouts_types.rs Outdated
@heykulthe
heykulthe dismissed stale reviews from AkshayaFoiger and Sakilmostak via d9fe997 August 11, 2026 14:20
@heykulthe
heykulthe removed the request for review from deepanshu-iiitu August 11, 2026 14:23
@AmitsinghTanwar007
AmitsinghTanwar007 added this pull request to the merge queue Aug 11, 2026
Merged via the queue into main with commit e6f3af5 Aug 11, 2026
19 checks passed
@AmitsinghTanwar007
AmitsinghTanwar007 deleted the feat/vop-changes branch August 11, 2026 15:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants